还是在Spring Cache的基础上,配置RedisConfig个MessageConfig以及自定义Cache和RedisManager。
如果本地没有,就去redis中读,如果都没有,就去数据库读,之后发送到redis,第一次读会读redis,之后会写入本地缓存,只要缓存不更新,就会去本地读。
1.自定义cache:RedisAndLocalCache1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119package com.zhaixin.config;
import org.springframework.cache.Cache;
import org.springframework.data.redis.cache.RedisCache;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
public class RedisAndLocalCache implements Cache {
ConcurrentHashMap<Object,Object> localCache = new ConcurrentHashMap<>();
RedisCache redisCache;
LocalAndRedisCacheManager localAndRedisCacheManager;
public RedisAndLocalCache(LocalAndRedisCacheManager localAndRedisCacheManager, RedisCache redisCache) {
this.localAndRedisCacheManager = localAndRedisCacheManager;
this.redisCache = redisCache;
}
public String getName() {
return redisCache.getName();
}
public Object getNativeCache() {
return redisCache.getNativeCache();
}
// 先从本地缓存读,有缓存直接返回,没有就从redis中读,并放入本地缓存
public ValueWrapper get(Object key) {
ValueWrapper valueWrapper = (ValueWrapper) localCache.get(key);
if(valueWrapper != null) {
System.out.println("从本机内存读取缓存");
return valueWrapper;
}else {
valueWrapper = redisCache.get(key);
System.out.println("从redis中读取缓存");
if(valueWrapper != null) {
localCache.put(key,valueWrapper);
}
}
return valueWrapper;
}
public <T> T get(Object key, Class<T> type) {
ValueWrapper value = get(key);
if (value != null && type != null && !type.isInstance(value)) {
throw new IllegalStateException(
"Cached value is not of required type [" + type.getName() + "]: " + value);
}
return (T) value;
}
public synchronized <T> T get(Object key, Callable<T> valueLoader) {
ValueWrapper result = get(key);
if (result != null) {
return (T) result.get();
}
T value = valueFromLoader(key, valueLoader);
put(key, value);
return value;
}
public void put(Object key, Object value) {
redisCache.put(key,value);
clearOtherJVM();
}
public ValueWrapper putIfAbsent(Object key, Object value) {
ValueWrapper valueWrapper = get(key);
if (valueWrapper == null){
put(key,value);
return null;
}else {
return valueWrapper;
}
}
public void evict(Object key) {
redisCache.evict(key);
clearOtherJVM();
}
public void clear() {
redisCache.clear();
clearOtherJVM();
}
// 通知其他节点,一级缓存更新
private void clearOtherJVM() {
localAndRedisCacheManager.publishMessage(getName());
}
// 清空一级缓存
public void clearLocalCache(){
localCache.clear();
}
private static <T> T valueFromLoader(Object key, Callable<T> valueLoader) {
try {
return valueLoader.call();
} catch (Exception e) {
throw new ValueRetrievalException(key, valueLoader, e);
}
}
}
2.自定义cachemanager:LocalAndRedisCacheManager1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46package com.zhaixin.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.core.RedisTemplate;
public class LocalAndRedisCacheManager extends RedisCacheManager {
RedisTemplate redisTemplate;
"${spring.cache.redis.topic:cache}") (
String topicName;
public LocalAndRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration, RedisTemplate redisTemplate) {
super(cacheWriter, defaultCacheConfiguration);
this.redisTemplate = redisTemplate;
}
// 通过自己实现的RedisAndLocalCache实现Cache接口来代替RedisCache
protected Cache decorateCache(Cache cache) {
return new RedisAndLocalCache(this, (RedisCache)cache);
}
// 发送广播
public void publishMessage(String value) {
System.out.println("发送清除缓存消息");
redisTemplate.convertAndSend(topicName,value);
}
// 接收消息清空本地缓存
public void receiver(String value) {
System.out.println("接收消息清除本地缓存");
RedisAndLocalCache cache = (RedisAndLocalCache)this.getCache(value);
if(cache != null) {
cache.clearLocalCache();
}
}
}
3.RedisConfig1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59package com.zhaixin.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
public class RedisConfig {
// 自定义RedisTemplate
"all") (
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
// 为了方便开发,一般直接使用<String,Object>
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// Json序列化配置
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
//String序列化
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//key采取String的方式序列化
template.setKeySerializer(stringRedisSerializer);
// hash的key采用String方式序列化
template.setHashKeySerializer(stringRedisSerializer);
// value的序列化方式选择jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashKeySerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
public LocalAndRedisCacheManager cacheManager(RedisConnectionFactory factory, RedisTemplate redisTemplate) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer()))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getKeySerializer()));
LocalAndRedisCacheManager cacheManager = new LocalAndRedisCacheManager(
RedisCacheWriter.lockingRedisCacheWriter(factory),config, redisTemplate);
return cacheManager;
}
}
4.MessageConfig1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50package com.zhaixin.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.Topic;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.data.redis.serializer.RedisSerializer;
import java.util.ArrayList;
import java.util.List;
public class MessageConfig {
private RedisTemplate redisTemplate;
"${spring.cache.redis.topic:cache}") (
String topicName;
RedisMessageListenerContainer container(MessageListenerAdapter listenerAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(redisTemplate.getConnectionFactory());
List<Topic> topicList = new ArrayList<>();
topicList.add(new PatternTopic(topicName));
container.addMessageListener(listenerAdapter, topicList);
return container;
}
// 消息侦听适配器,能够将消息委托给目标侦听器处理方法
MessageListenerAdapter listenerAdapter(final LocalAndRedisCacheManager cacheManager) {
return new MessageListenerAdapter(new MessageListener() {
public void onMessage(Message message, byte[] bytes) {
RedisSerializer<?> valueSerializer = redisTemplate.getValueSerializer();
RedisSerializer<?> keySerializer = redisTemplate.getKeySerializer();
String body = (String) valueSerializer.deserialize(message.getBody());
cacheManager.receiver(body);
}
});
}
}